#include <stdio.h>
#include <stdlib.h>
#include <gccore.h>
#include <wiiuse/wpad.h>
#include "wiisprite.h"
#include <fat.h>

#include <vector.h>

#include "LevelBuilder.h"
#include "level.h"

#include "mainmenutree.h"

#include "pointer.h"

#include "soundmanager.h"

#include "leveldata.h"

#include "filebrowse.h"

#include "OnScreenKeyboard.h"

#include "credits.h"

#include "highscores.h"
#include "helpscreen.h"

#include "mainintro.h"

#include "yesnobox.h"

#include "settings.h"

#include "networktools.h"

#include <ogc/lwp.h>
#include <ogc/mutex.h>

using namespace wsp;

Sprite portiiMainSprite;
Image* portiiMainImg;

Sprite gameSprite;
Image* gameImg;

Sprite builderSprite;
Image* builderImg;

Sprite pauseSprite;
Image* pauseImg;

Sprite pause2Sprite;
Image* pause2Img;

Sprite winSprite;
Image* winImg;

Sprite saveSprite;
Image* savePassImg;
Image* saveFailImg;

Sprite loadSprite;
Image* loadPassImg;
Image* loadFailImg;

Image* continueImg;
YesNoBox* yesNoBox;

Sprite bubbleSprite;
Image* bubbleImg;

Sprite netSprite;
Image* connectedImg;
Image* connectingImg;
Image* notConnectedImg;

Sprite updateSprite;
Image* updatingImg;
Image* updateFailedImg;
Image* updateAvailImg;
Image* updateCompleteImg;

Settings* settings;

Level* level;

LevelBuilder* levelBuilder;

SoundManager* soundManager;

Pointer* pointer;

FileBrowse* filebrowse;

OnScreenKeyboard* osk;

Credits* credits;

GameWindow gwd;

HighScores* highscores;
HelpScreen* helpScreen;

MainIntro* mainIntro;

bool _cheat = false;

extern u8 intro_png[];
extern u8 portii_main_png[];
extern u8 game_main_png[];
extern u8 builder_main_png[];

extern u8 win_main_png[];
extern u8 pause_main_png[];
extern u8 pause_main_2_png[];

extern u8 save_pass_png[];
extern u8 save_fail_png[];
extern u8 load_pass_png[];
extern u8 load_fail_png[];
extern u8 bubblebg_png[];

extern u8 continue_png[];
extern u8 yesNoBg_png[];
extern u8 yes_png[];
extern u8 no_png[];
extern u8 yesOver_png[];
extern u8 noOver_png[];

extern u8 connected_png[];
extern u8 connecting_png[];
extern u8 notConnected_png[];

extern u8 updateAvail_png[];
extern u8 updateComplete_png[];
extern u8 updateFailed_png[];
extern u8 updating_png[];

Image* yesNoBgImg;
Image* yesImg;
Image* noImg;
Image* yesOverImg;
Image* noOverImg;

MainMenuTree* mainMenuTree;

/* Story Mode Level queue */
std::vector<LevelData*> _storyLevels;
int level_index = 0;

/* Story Mode Levels */
extern u8 story_0_portii[];
extern u8 story_1_portii[];
extern u8 story_2_portii[];
extern u8 story_3_portii[];
extern u8 story_4_portii[];
extern u8 story_5_portii[];
extern u8 story_6_portii[];
extern u8 story_7_portii[];
extern u8 story_8_portii[];
extern u8 story_9_portii[];
extern u8 story_10_portii[];
extern u8 story_11_portii[];
extern u8 story_12_portii[];
extern u8 story_13_portii[];
extern u8 story_14_portii[];
extern u8 story_15_portii[];
extern u8 story_16_portii[];
extern u8 story_17_portii[];
extern u8 story_18_portii[];

//NETWORK STUFF
NetworkTools* netTools;

lwpq_t netThreadQ;
lwp_t netThread;
int rc, t;

#define THREADSTACK 8192	/*** Default 8k stack space ***/

u8 threadstack[THREADSTACK];

mutex_t mutexList[NetMutex::SIZE];
bool    mutexVal[NetMutex::SIZE];

#define MAX_ATTEMPTS 3
//END NET STUFF

int curVersion = 1;

bool GetMutexValue(NetMutex::Type type)
{
	bool ret = true;
	LWP_MutexLock(mutexList[type]);
	ret = mutexVal[type];
	LWP_MutexUnlock(mutexList[type]);
	
	return ret;
}

void SetMutexValue(NetMutex::Type type, bool val)
{
	LWP_MutexLock(mutexList[type]);
	mutexVal[type] = val;
	LWP_MutexUnlock(mutexList[type]);
}

void InitMutexList()
{
	for(int i = 0; i < NetMutex::SIZE; i++)
	{
	    LWP_MutexInit (&mutexList[i], false);
		SetMutexValue((NetMutex::Type)i, false);
	}
}

void *NetMain(void *threadid)
{
	int tid;
	tid = (int)threadid;
	
	bool checkUpdate  = true;

	int attempts = 0;
	
	while(GetMutexValue(NetMutex::NET_CONNECTED) == false && attempts < MAX_ATTEMPTS)
	{
		bool b = netTools->Connect();
		
		SetMutexValue(NetMutex::NET_CONNECTED, b);
		
		if(GetMutexValue(NetMutex::NET_CONNECTED) == false)			
                usleep(5000);

		attempts++;
	};
	
	while(GetMutexValue(NetMutex::NET_CONNECTED))
	{
		//Main Networking
		
		/*Check for update*/
		if(checkUpdate)
		{
			if(netTools->CheckPortiiUpdate(&curVersion))
			{
				SetMutexValue(NetMutex::UPDATE_AVAIL, true);
			}
			
			checkUpdate = false;
		}
		
		/*Update Portii*/
		if(GetMutexValue(NetMutex::DO_UPDATE))
		{
			if(netTools->UpdatePortii())
			{
				//Update completed succesfully
				SetMutexValue(NetMutex::UPDATE_AVAIL, false);
				SetMutexValue(NetMutex::UPDATE_STATUS, true);
			}
			else
			{
				//Update failed!
				SetMutexValue(NetMutex::UPDATE_AVAIL, false);
				SetMutexValue(NetMutex::UPDATE_STATUS, false);
			}
			
			SetMutexValue(NetMutex::DO_UPDATE,false);
		}	
        usleep(2000);
			
	}
	
    LWP_SuspendThread(tid);

}


void wait_for_press()
{
        while(1) {

                // Call WPAD_ScanPads each loop, this reads the latest controller states
                WPAD_ScanPads();

                // WPAD_ButtonsDown tells us which buttons were pressed in this loop
                // this is a "one shot" state which will not fire again until the button has been released
                u32 pressed = WPAD_ButtonsDown(0);

                // We return to the launcher application via exit
                if ( pressed & WPAD_BUTTON_A ) break;
        }
}

void init_all_levels()
{
	_storyLevels.push_back(new LevelData(story_0_portii));
	_storyLevels.push_back(new LevelData(story_1_portii));
	_storyLevels.push_back(new LevelData(story_2_portii));
	_storyLevels.push_back(new LevelData(story_3_portii));
	_storyLevels.push_back(new LevelData(story_4_portii));
	_storyLevels.push_back(new LevelData(story_5_portii));
	_storyLevels.push_back(new LevelData(story_6_portii));
	_storyLevels.push_back(new LevelData(story_7_portii));
	_storyLevels.push_back(new LevelData(story_8_portii));
	_storyLevels.push_back(new LevelData(story_9_portii));
	_storyLevels.push_back(new LevelData(story_10_portii));
	_storyLevels.push_back(new LevelData(story_11_portii));
	_storyLevels.push_back(new LevelData(story_12_portii));
	_storyLevels.push_back(new LevelData(story_13_portii));
	_storyLevels.push_back(new LevelData(story_14_portii));
	_storyLevels.push_back(new LevelData(story_15_portii));
	_storyLevels.push_back(new LevelData(story_16_portii));
	_storyLevels.push_back(new LevelData(story_17_portii));
	_storyLevels.push_back(new LevelData(story_18_portii));
}

bool level_select()
{

	filebrowse->PopulateList();
	
	int index = highscores->GetLevelsComplete();
	
	if(highscores->GetLevelsComplete() > (int)_storyLevels.size())
		index = (int)_storyLevels.size();
	
	for(int i = index-1; i >= 0; i--)
	{
		char buff[200];
		sprintf(buff, "storylevel_%d", i);
		
		filebrowse->InsertFront(buff);
	}
	
	while(filebrowse->Update(pointer, level->GameMode()))
	{
		gwd.Flush();
	}

	if(filebrowse->IsCancelled())
	{
		return false;
	}
	else
	{
		if(filebrowse->GetSelectedFile() != NULL)
		{
			if(filebrowse->GetSelectedFileIndex() != -1 && filebrowse->GetSelectedFileIndex() < highscores->GetLevelsComplete())
			{
				if(levelBuilder->LoadFromBuffer((char*)(_storyLevels[filebrowse->GetSelectedFileIndex()]->GetData())))
				{
					level->SetName(filebrowse->GetSelectedFile());
					level->Init(levelBuilder);
					return true;
				}
				else
				{
					return false;
				}
			}
			else
			{
				if(levelBuilder->LoadFromFile(filebrowse->GetSelectedFile()))
				{
					level->SetName(filebrowse->GetSelectedFile());
					level->Init(levelBuilder);
					return true;
				}
				else
				{
					return false;
				}
			}
		}
	}
	
	return false;
}

bool load_next_level()
{
	
	if(level_index < (int)_storyLevels.size())
	{
		if(levelBuilder->LoadFromBuffer((char*)(_storyLevels[level_index]->GetData())))
		{			
			level->Init(levelBuilder);
			char buff[200];
			sprintf(buff, "storylevel_%d", level_index);
			level->SetName(buff);
			level_index++;
			return true;
		}
		else
		{
			mainMenuTree->Render();
			loadSprite.SetImage(loadFailImg);
			loadSprite.Draw();
			
			gwd.Flush();
			wait_for_press();
			
			mainMenuTree->ChangeActiveMenu(MyMenu::MAIN);
			
		}
	}
	
	return false;
}

void level_end()
{
	bool run_next = true;
	bool isHighScore = false;

	if(level->GameMode() == GameMode::STORY)
	{
		highscores->SetLevelsComplete(level_index);
		highscores->SetLevelIndex(level_index);
		
		if(level_index == (int)_storyLevels.size())
		{
			soundManager->PlaySound(Sound::STILL_ALIVE, 1);

			highscores->SetInProgress(false);

			credits->RollCredits(&gwd);
			mainMenuTree->ChangeActiveMenu(MyMenu::MAIN);
			
			if(_cheat)
			{
				soundManager->PlaySound(Sound::STILL_DEAD, 1);
			}
			else
			{
				soundManager->PlaySound(Sound::PORTII,1);
			}	
			
			run_next = false;
			level_index = 0;
		}
	}
	else if(level->GameMode() == GameMode::TIMED)
	{
		//TODO Keep time and return here
		if(highscores->IsHighScore(GameMode::TIMED, (char*)level->GetName(), level->GetTime()))
			isHighScore = true;
	}
	else if(level->GameMode() == GameMode::PORTAL_COUNT)
	{
		//TODO Keep time and return here
		if(highscores->IsHighScore(GameMode::PORTAL_COUNT, (char*)level->GetName(), level->GetPortalCount()))
			isHighScore = true;
	}
	
	if(run_next)
	{
		level->RenderSummary(isHighScore);
		gwd.Flush();
		wait_for_press();
		mainMenuTree->ChangeActiveMenu(MyMenu::WON_GAME);
	}
}

void init_system()
{
	fatInitDefault();
	
	// Create the game window and initalise the VIDEO subsystem
	gwd.InitVideo();

	gwd.SetBackground((GXColor){ 255, 255, 255, 255 });

	// Initialise Wiimote
	WPAD_Init();
	WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
}

void init_portii()
{
    settings = new Settings();
	//settings->Load();

	curVersion = settings->GetVersion();

	netTools = new NetworkTools(settings);

	soundManager = new SoundManager(settings);
	
	level = new Level(soundManager, settings);
	
	pointer = new Pointer();
	
	levelBuilder = new LevelBuilder(soundManager);
	
	osk = new OnScreenKeyboard(&gwd);
	
	credits = new Credits();
	
	highscores = new HighScores(settings);

	highscores->Load();
	
	filebrowse = new FileBrowse(highscores);
	
	helpScreen = new HelpScreen();
	
	//mainIntro = new MainIntro(soundManager);
	
	bubbleImg = new Image();
    if(bubbleImg->LoadImage(bubblebg_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	bubbleSprite.SetImage(bubbleImg);
	bubbleSprite.SetPosition(0,50);
	
	portiiMainImg = new Image();
    if(portiiMainImg->LoadImage(portii_main_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
   
    portiiMainSprite.SetImage(portiiMainImg);
	portiiMainSprite.SetPosition(100,30);

	continueImg = new Image();
    if(continueImg->LoadImage(continue_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);

	gameImg = new Image();
    if(gameImg->LoadImage(game_main_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
   
    gameSprite.SetImage(gameImg);
	gameSprite.SetPosition(100,50);

	builderImg = new Image();
    if(builderImg->LoadImage(builder_main_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
  
    builderSprite.SetImage(builderImg);
	builderSprite.SetPosition(100,50);
	
	savePassImg = new Image();
    if(savePassImg->LoadImage(save_pass_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	
        saveFailImg = new Image();
    if(saveFailImg->LoadImage(save_fail_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
   
    saveSprite.SetImage(savePassImg);
	saveSprite.SetPosition(150,100);
	
	loadPassImg = new Image();
    if(loadPassImg->LoadImage(load_pass_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);

	loadFailImg = new Image();
    if(loadFailImg->LoadImage(load_fail_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
   
    loadSprite.SetImage(loadPassImg);
	loadSprite.SetPosition(150,100);

	pauseImg = new Image();
    if(pauseImg->LoadImage(pause_main_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
  
    pauseSprite.SetImage(pauseImg);
	pauseSprite.SetPosition(100,50);
	
	pause2Img = new Image();
    if(pause2Img->LoadImage(pause_main_2_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
  
    pause2Sprite.SetImage(pause2Img);
	pause2Sprite.SetPosition(100,50);
	
	winImg = new Image();
    if(winImg->LoadImage(win_main_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
  
    winSprite.SetImage(winImg);
	winSprite.SetPosition(100,50);
	
    mainMenuTree = new MainMenuTree();
    mainMenuTree->ChangeActiveMenu(MyMenu::MAIN);

	yesNoBgImg = new Image();
    if(yesNoBgImg->LoadImage(yesNoBg_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	yesImg     = new Image();
    if(yesImg->LoadImage(yes_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	noImg      = new Image();
    if(noImg->LoadImage(no_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	yesOverImg = new Image();
    if(yesOverImg->LoadImage(yesOver_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	noOverImg  = new Image();
    if(noOverImg->LoadImage(noOver_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);

	yesNoBox = new YesNoBox(yesNoBgImg, yesImg, yesOverImg, noImg, noOverImg);

	connectedImg    = new Image();
    if(connectedImg->LoadImage(connected_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	connectingImg    = new Image();
    if(connectingImg->LoadImage(connecting_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	notConnectedImg  = new Image();
    if(notConnectedImg->LoadImage(notConnected_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);

	netSprite.SetPosition(590, 440);
	netSprite.SetImage(notConnectedImg);
		
	updatingImg      = new Image();
    if(updatingImg->LoadImage(updating_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	
	updateFailedImg  = new Image();
    if(updateFailedImg->LoadImage(updateFailed_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	
	updateAvailImg   = new Image();
    if(updateAvailImg->LoadImage(updateAvail_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);

	updateCompleteImg      = new Image();
    if(updateCompleteImg->LoadImage(updateComplete_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)exit(0);
	
	init_all_levels();	
	
}

bool level_builder_main()
{
	while(levelBuilder->Update())
	{
		levelBuilder->Render(0,0, false);
		gwd.Flush();
	}

	return true;
}

bool game_main()
{
	while(level->Update(pointer))
	{
		ir_t ir; // The struct for infrared
		
		WPAD_IR(WPAD_CHAN_0, &ir); // Let's get our infrared data

		pointer->SetPosition(ir.sx-200, ir.sy-250);
		pointer->SetRotation(ir.angle/2); // Set angle/2 to translate correctly
		
		level->PreRender();
		
		levelBuilder->Render(level->GetOffsetX(), level->GetOffsetY(), true);

		bool ret_val = level->Render();
		
		if(!ret_val)
			pointer->Render();
		
		gwd.Flush();
			
		if(ret_val) wait_for_press();
		
		
	} 

	if(level->Won())
		return true;
	
    return false;
}

void play_intro()
{
	//"Fade in"
	Sprite introSprite;
	Image* introImg = new Image();
	if(introImg->LoadImage(intro_png, IMG_LOAD_TYPE_BUFFER) != IMG_LOAD_ERROR_NONE)
		exit(0);
	
	introSprite.SetImage(introImg);
	introSprite.SetPosition(192,120);
	
	introSprite.SetTransparency(0);
	gwd.Flush();
	
        soundManager->PlaySound(Sound::INTRO,0);
	
	for(int i = 0; i < 255; i++) //255 *2
	{
		WPAD_ScanPads();
			
		u16 btnsheld = WPAD_ButtonsHeld(0);

		if(btnsheld & WPAD_BUTTON_A && btnsheld & WPAD_BUTTON_B)
		{
			_cheat = true;
			
		}
		
		introSprite.SetTransparency(i);
		introSprite.Draw();
		gwd.Flush();
	}

        if(_cheat)
           gwd.SetBackground((GXColor){ 100, 100, 100, 100 });
        else
           gwd.SetBackground((GXColor){ 250, 250, 250, 100 });
}

void FadeToBlack()
{

	Quad fadeQuad;
	GXColor fill_color;
	fill_color.r = 0;
	fill_color.g = 0;
	fill_color.b = 0;
	fill_color.a = 0;
	fadeQuad.SetFillColor(fill_color);
	fadeQuad.SetWidth(700);
	fadeQuad.SetHeight(700);
	fadeQuad.SetPosition(-30,-30);
	int i = 0;
	
	while(i < 255)
	{
		switch(mainMenuTree->GetCurrentActiveMenu())
		{
			case MyMenu::MAIN:
				bubbleSprite.Draw();
				portiiMainSprite.Draw();
				break;
			case MyMenu::GAME:
				bubbleSprite.Draw();
				gameSprite.Draw();
				break;
			case MyMenu::BUILDER:
				bubbleSprite.Draw();
				builderSprite.Draw();
				break;
			case MyMenu::SUB_GAME:
				bubbleSprite.Draw();
				pauseSprite.Draw();
				break;
			case MyMenu::SUB_BUILDER:
				bubbleSprite.Draw();
				pause2Sprite.Draw();
				break;
			case MyMenu::SUB_TEST:
				bubbleSprite.Draw();
				pauseSprite.Draw();
				break;
			case MyMenu::WON_GAME:
				bubbleSprite.Draw();
				winSprite.Draw();
				break;
			default:
				break;
		}
		mainMenuTree->Render();

		pointer->Render();
		
		fill_color.a = i;
		fadeQuad.SetFillColor(fill_color);
		fadeQuad.Draw();
		i+=15;
		gwd.Flush();
	}
	
	fill_color.a = 255;
	fadeQuad.SetFillColor(fill_color);
	fadeQuad.Draw();
	gwd.Flush();
				
}

void main_menu()
{
	if(_cheat)
	{
		soundManager->PlaySound(Sound::STILL_DEAD, 1);
		level->SetTimeStep(2.0f / 60.0f);
	}
	else
	{
		soundManager->PlaySound(Sound::PORTII,1);
	}
	
	while(true)
	{
		ir_t ir; // The struct for infrared
		
		WPAD_IR(WPAD_CHAN_0, &ir); // Let's get our infrared data

		pointer->SetPosition(ir.sx-200, ir.sy-250);
		pointer->SetRotation(ir.angle/2); // Set angle/2 to translate correctly
	
		
		/*Network Test stuff
		  
		  This section is for network testing.... assume this does NOT work until
		  you hear otherwise.
		  
		  */
		  
		  /* Update Testing
			if(netTools->CheckPortiiUpdate())
			{
				//TODO Prompt user that an update exists
				
					//I think we just want to add a button to the main menu screen to indicate an update is avail
					//If that button gets clicked...
					netTools->UpdatePortii();
			}
		  */
		
		  /* Level Download Testing
		    netTools->DownloadNetworkLevel("level_test.portii");
		  */
	
	
		if(mainMenuTree->Update(pointer))
		{
            soundManager->PlaySound(Sound::MENU_CLICK_FX,0);
			
			switch(mainMenuTree->GetCurrentActiveMenu())
			{
				case MyMenu::MAIN:
					if(mainMenuTree->GetSelectedItem() == 0) //New Game
					{
						mainMenuTree->ChangeActiveMenu(MyMenu::GAME, true);
					}
					else if(mainMenuTree->GetSelectedItem() == 1) //Level Builder
					{
						mainMenuTree->ChangeActiveMenu(MyMenu::BUILDER, true);
					}
					else if(mainMenuTree->GetSelectedItem() == 2) //Help
					{
						while(helpScreen->Update())
							gwd.Flush();
							
					}
					else if(mainMenuTree->GetSelectedItem() == 3) //Exit
					{
						//Disconnect network
						SetMutexValue(NetMutex::NET_CONNECTED, false);
						highscores->Save();
						settings->Save();
						usleep(5000);
						return;
					}
					break;
				case MyMenu::GAME:
					if(mainMenuTree->GetSelectedItem() == 0) //Story
					{
						level->SetMode(GameMode::STORY);
						level_index = 0;
						
						if(highscores->IsInProgress())
						{
							if(yesNoBox->GetYesNo(pointer, &gwd, continueImg))
							{
								level_index = highscores->GetLevelIndex();
							}
						}
						
						highscores->SetInProgress(true);
						highscores->SetCustomStory(false);
						
						if(load_next_level())
						{
							FadeToBlack();
							if(game_main())
							{
								level_end();
							}
							else
							{
								mainMenuTree->ChangeActiveMenu(MyMenu::SUB_GAME, true);
							}
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 1) //Timed
					{
						level->SetMode(GameMode::TIMED);
						level_index = 0;
						filebrowse->ClearIndex();
						
						SELECT_TIMED:
						if(level_select())
						{
							if(game_main())
							{
								level_end();
								goto SELECT_TIMED;
							}
							else
							{
								mainMenuTree->ChangeActiveMenu(MyMenu::SUB_GAME, true);
							}
						}
						else
						{
							mainMenuTree->ChangeActiveMenu(MyMenu::GAME, false);
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 2) //Least Portals
					{
						level->SetMode(GameMode::PORTAL_COUNT);
						level_index = 0;
						filebrowse->ClearIndex();
						
						SELECT_PORTAL:						
						if(level_select())
						{
							if(game_main())
							{
								level_end();
								goto SELECT_PORTAL;
							}
							else
							{
								mainMenuTree->ChangeActiveMenu(MyMenu::SUB_GAME, true);
							}
						}
						else
						{
							mainMenuTree->ChangeActiveMenu(MyMenu::GAME, false);
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 3) //Back
					{
						mainMenuTree->ChangeActiveMenu(MyMenu::MAIN, true);
					}
					break;
				case MyMenu::SUB_GAME:
					if(mainMenuTree->GetSelectedItem() == 0) //return
					{
						FadeToBlack();
						if(game_main())
						{
							level_end();
						}
						else
						{
							mainMenuTree->ChangeActiveMenu(MyMenu::SUB_GAME, false);
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 1) //restart
					{
						level->Reset();
						
						FadeToBlack();
						if(game_main())
						{
							level_end();
						}
						else
						{
							mainMenuTree->ChangeActiveMenu(MyMenu::SUB_GAME, false);
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 2) //quit
					{
						mainMenuTree->ChangeActiveMenu(MyMenu::GAME, true);
					}
					break;
				case MyMenu::WON_GAME:
					if(mainMenuTree->GetSelectedItem() == 0) //next level
					{
						if(load_next_level())
						{
							FadeToBlack();
							if(game_main())
							{
								level_end();
							}
							else
							{
								mainMenuTree->ChangeActiveMenu(MyMenu::SUB_GAME, true);
							}
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 1) //quit
					{
						mainMenuTree->ChangeActiveMenu(MyMenu::GAME, true);
					}
					break;
				case MyMenu::BUILDER:
					if(mainMenuTree->GetSelectedItem() == 0) //New
					{
						levelBuilder->Init();
						level_builder_main();
						mainMenuTree->ChangeActiveMenu(MyMenu::SUB_BUILDER, true);
					}
					else if(mainMenuTree->GetSelectedItem() == 1) //Load
					{
						filebrowse->ClearIndex();
						filebrowse->PopulateList();
						
						while(filebrowse->Update(pointer))
						{
								gwd.Flush();
						}
					
						if(filebrowse->IsCancelled())
						{
						        mainMenuTree->ChangeActiveMenu(MyMenu::BUILDER, false);
						}
						else
						{
							if(filebrowse->GetSelectedFile() != NULL)
							{
								if(levelBuilder->LoadFromFile(filebrowse->GetSelectedFile()))
								{
						            mainMenuTree->ChangeActiveMenu(MyMenu::SUB_BUILDER, true);
									mainMenuTree->Render();
									loadSprite.SetImage(loadPassImg);
									loadSprite.Draw();
									
									gwd.Flush();
									
									wait_for_press();
									
									level_builder_main();
								}
								else
								{
									mainMenuTree->Render();
									loadSprite.SetImage(loadFailImg);
									loadSprite.Draw();
									
									gwd.Flush();
									wait_for_press();
						                        mainMenuTree->ChangeActiveMenu(MyMenu::BUILDER, false);
								}
							}
							else
							{
								mainMenuTree->ChangeActiveMenu(MyMenu::BUILDER, false);
							}
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 2) //Back
					{
						mainMenuTree->ChangeActiveMenu(MyMenu::MAIN, true);
					}
					break;
				case MyMenu::SUB_BUILDER:
					if(mainMenuTree->GetSelectedItem() == 0) //Return
					{
						level_builder_main();
					}
					if(mainMenuTree->GetSelectedItem() == 1) //Test
					{
						level->Init(levelBuilder);
                                                //soundManager->PlaySound(Sound::ENTER_TEST,0);
						FadeToBlack();
						if(game_main())
						{
							level->RenderSummary(false);
							gwd.Flush();
							wait_for_press();
						}
						
						mainMenuTree->ChangeActiveMenu(MyMenu::SUB_TEST, true);
					}
					else if(mainMenuTree->GetSelectedItem() == 2) //Save
					{
						char* lastFile = filebrowse->GetSelectedFile();
						
						char* fname;
						
						if(lastFile == NULL)
						{
							fname = osk->GetString();
							
						}
						else
						{
							fname = osk->EditString(lastFile);
						}
						
						
						if(fname != NULL)
						{
							
							if(levelBuilder->Save(fname))
							{
								mainMenuTree->Render();
								saveSprite.SetImage(savePassImg);
								saveSprite.Draw();
								gwd.Flush();
								
								wait_for_press();
							}
							else
							{
								mainMenuTree->Render();
								saveSprite.SetImage(saveFailImg);
								saveSprite.Draw();
								gwd.Flush();
								
								wait_for_press();
							}
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 3) //Quit
					{
						if(levelBuilder->UnsavedChanges())
						{
							if(yesNoBox->GetYesNo(pointer, &gwd))
							{
								mainMenuTree->ChangeActiveMenu(MyMenu::BUILDER, true);
							}
							else
							{
						        mainMenuTree->ChangeActiveMenu(MyMenu::SUB_BUILDER, false);
							}
						}
						else
						{
							mainMenuTree->ChangeActiveMenu(MyMenu::BUILDER, true);
						}
					}
					break;
				case MyMenu::SUB_TEST:
					if(mainMenuTree->GetSelectedItem() == 0) //return
					{
						FadeToBlack();
						if(game_main())
						{
							level->RenderSummary(false);
							gwd.Flush();
							wait_for_press();
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 1) //restart
					{
						level->Reset();
						FadeToBlack();
						if(game_main())
						{
							level->RenderSummary(false);
							gwd.Flush();
							wait_for_press();
						}
					}
					else if(mainMenuTree->GetSelectedItem() == 2) //Quit
					{
						mainMenuTree->ChangeActiveMenu(MyMenu::SUB_BUILDER, true);
					}
					break;
				default:
					break;
			}
		}
		
		pointer->DefaultImage();
		
		switch(mainMenuTree->GetCurrentActiveMenu())
		{
			case MyMenu::MAIN:
				bubbleSprite.Draw();
				portiiMainSprite.Draw();
				break;
			case MyMenu::GAME:
				bubbleSprite.Draw();
				gameSprite.Draw();
				break;
			case MyMenu::BUILDER:
				bubbleSprite.Draw();
				builderSprite.Draw();
				break;
			case MyMenu::SUB_GAME:
				bubbleSprite.Draw();
				pauseSprite.Draw();
				break;
			case MyMenu::SUB_BUILDER:
				bubbleSprite.Draw();
				pause2Sprite.Draw();
				break;
			case MyMenu::SUB_TEST:
				bubbleSprite.Draw();
				pauseSprite.Draw();
				break;
			case MyMenu::WON_GAME:
				bubbleSprite.Draw();
				winSprite.Draw();
				break;
			default:
				break;
		}

		mainMenuTree->Render();

		if(settings->IsNetworkEnabled())
		{
			if(GetMutexValue(NetMutex::NET_CONNECTED))
			{
				netSprite.SetImage(connectedImg);
			}
			else if(GetMutexValue(NetMutex::CONNECTING))
			{
				netSprite.SetImage(connectingImg);
			}
			else
			{
				netSprite.SetImage(notConnectedImg);
			}
			netSprite.Draw();
		}
		
		if(GetMutexValue(NetMutex::UPDATE_AVAIL))
		{
			SetMutexValue(NetMutex::DO_UPDATE, yesNoBox->GetYesNo(pointer, &gwd, updateAvailImg));
			SetMutexValue(NetMutex::UPDATE_AVAIL, false);
			
			if(GetMutexValue(NetMutex::DO_UPDATE))
			{
				while(GetMutexValue(NetMutex::DO_UPDATE))
				{
					//Draw updating, exit when done.
					updateSprite.SetImage(updatingImg);
					updateSprite.Draw();
					gwd.Flush();
					usleep(5000);
				}
				
				if(GetMutexValue(NetMutex::UPDATE_STATUS))
				{
					SetMutexValue(NetMutex::NET_CONNECTED, false);
					updateSprite.SetImage(updateCompleteImg);
					updateSprite.Draw();
					gwd.Flush();
					wait_for_press();
					settings->SetVersion(curVersion);
					highscores->Save();
					settings->Save();
					return;
				}
				else
				{
					updateSprite.SetImage(updateFailedImg);
					updateSprite.Draw();
					gwd.Flush();
					wait_for_press();
				}
			}
			
		}
		
		pointer->Render();
		gwd.Flush();
	}
}


void init_net()
{
	InitMutexList();
	
	if(settings->IsNetworkEnabled())
	{
		/*Setup network Threading */
			/*** Create Both Threads ***/
			/* Priority 80-128 (80 high, 128 low)*/
		rc = LWP_CreateThread (&netThread, NetMain, NULL, threadstack, THREADSTACK, 120);

		if(rc!=0) {
		  //Net init failed!
		  SetMutexValue(NetMutex::NET_CONNECTED, false);
		}
	}
}

int main(int argc, char **argv)
{
	init_system();
	
	init_portii();

    //game intro
	play_intro();
	
	init_net();
	//mainIntro->Play(&gwd);
	
	//main game loop
	main_menu();

	FadeToBlack();

	return 0;
}
